runatlantis / atlantis

Terraform Pull Request Automation
https://www.runatlantis.io
Other
7.82k stars 1.06k forks source link

Different Terraform versions #4935

Closed hakuno closed 1 month ago

hakuno commented 1 month ago

Community Note


Overview of the Issue

From built-in step

- plan

Results in Terraform 1.9.6

From custom step

- run: terraform plan -input=false -refresh -out $PLANFILE

Results in Terraform 1.9.5

So if I use both

β•·
β”‚ Error: Failed to read plan from plan file
β”‚ 
β”‚ Cannot read the plan from the given plan file: plan file was created by
β”‚ Terraform 1.9.5, but this is 1.9.6; plan files cannot be transferred
β”‚ between different Terraform versions.
β•΅

Reproduction Steps

Logs

Environment details

Atlantis v0.29.0

Additional Context

dosubot[bot] commented 1 month ago

Hello @hakuno! I'm here to help you with any bugs, questions, or contributions you have. Let's tackle this Terraform version issue together while we wait for a human maintainer.

I found a similar open issue that might be relevant to your problem: Using previous versions of Terraform no longer works. This issue was last updated on June 27, 2024, and currently has no comments or solution [1].

To resolve the error "Failed to read plan from plan file" when using different Terraform versions (1.9.5 and 1.9.6) in Atlantis v0.29.0, you need to ensure that the plan file is compatible with the Terraform version being used. The error typically occurs because the plan file generated by one version of Terraform is not readable by another version.

Here are some steps to ensure compatibility:

  1. Use the same Terraform version for both planning and applying: Ensure that the Terraform version used to create the plan file is the same as the one used to apply it. This can be managed by setting the TerraformVersion in the ProjectContext.

  2. Check for remote operations: If using Terraform Cloud or Enterprise, ensure that the remote operations are correctly handled, as the plan file might not be saved locally.

Here is a snippet from the planStepRunner that shows how the plan command is built and executed:

func (p *planStepRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) {
    tfVersion := p.DefaultTFVersion
    if ctx.TerraformVersion != nil {
        tfVersion = ctx.TerraformVersion
    }

    planFile := filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName))
    planCmd := p.buildPlanCmd(ctx, extraArgs, path, tfVersion, planFile)
    output, err := p.TerraformExecutor.RunCommandWithVersion(ctx, filepath.Clean(path), planCmd, envs, tfVersion, ctx.Workspace)
    if p.isRemoteOpsErr(output, err) {
        ctx.Log.Debug("detected that this project is using TFE remote ops")
        return p.remotePlan(ctx, extraArgs, path, tfVersion, planFile, envs)
    }
    if err != nil {
        return output, err
    }
    return p.fmtPlanOutput(output, tfVersion), nil
}

Ensure that the TerraformVersion in the ProjectContext is set correctly to match the version used for both planning and applying. If you are using remote operations, the remotePlan method will handle the creation of a "fake" plan file to ensure compatibility [2].

Additionally, you can enforce the use of a specific Terraform version across all steps by setting the --default-tf-version flag or specifying the terraform_version key in the atlantis.yaml file for a specific repo or project.

Example using --default-tf-version flag:

--default-tf-version=v1.3.7

Example using atlantis.yaml:

version: 3
projects:
- dir: .
  terraform_version: v1.1.5

Alternatively, you can use the required_version key in the Terraform configuration block to specify an exact version or a version constraint.

Example using required_version in Terraform configuration:

terraform {
  required_version = "= 1.2.9"
}

Atlantis will automatically download the latest version that fulfills the specified constraint [3][4].

To continue talking to Dosu, mention @dosu.

hakuno commented 1 month ago

So I see It needs to append an environment variable as terraform${ATLANTIS_TERRAFORM_VERSION}