Skip to content

feat: Download default terraform version when minor version mismatches #1775

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jun 22, 2022
Next Next commit
download default terraform version when minor version mismatches
  • Loading branch information
AbhineetJain committed Jun 22, 2022
commit b25b4b15c81fcface5dbbfd0d21e253e439faf36
54 changes: 43 additions & 11 deletions provisioner/terraform/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package terraform

import (
"context"
"os/exec"
"path/filepath"
"regexp"
"strings"

"github.com/cli/safeexec"
"github.com/hashicorp/go-version"
Expand All @@ -17,6 +20,7 @@ import (
// This is the exact version of Terraform used internally
// when Terraform is missing on the system.
const terraformVersion = "1.1.9"
const versionDelimiter = "."

var (
// The minimum version of Terraform supported by the provisioner.
Expand Down Expand Up @@ -45,7 +49,46 @@ type ServeOptions struct {
func Serve(ctx context.Context, options *ServeOptions) error {
if options.BinaryPath == "" {
binaryPath, err := safeexec.LookPath("terraform")
var downloadTerraform bool
if err != nil {
downloadTerraform = true
} else {
// If the "coder" binary is in the same directory as
// the "terraform" binary, "terraform" is returned.
//
// We must resolve the absolute path for other processes
// to execute this properly!
absoluteBinary, err := filepath.Abs(binaryPath)
if err != nil {
return xerrors.Errorf("absolute: %w", err)
}
// Checking the installed version of Terraform.
output, err := exec.Command(absoluteBinary, "version").Output()
if err != nil {
return xerrors.Errorf("terraform version: %w", err)
}
// The output for `terraform version` is:
// Terraform v1.2.1
// on linux_amd64
versionRegex := regexp.MustCompile("Terraform v(.+)\n?.*")
match := versionRegex.FindStringSubmatch(string(output))
if match != nil {
// match[0] is the entire string.
// match[1] is the matched substring.
version := match[1]
terraformMinorVersion := strings.Join(strings.Split(terraformVersion, versionDelimiter)[:2], versionDelimiter)
if !strings.HasPrefix(version, terraformMinorVersion) {
downloadTerraform = true
}
} else {
// Download the required Terraform version when unable to determine the existing one.
downloadTerraform = true
}
if !downloadTerraform {
options.BinaryPath = absoluteBinary
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The terraform-exec library already handles most of this for us!

https://github.com/coder/coder/blob/main/provisioner/terraform/provision.go#L63-L70

}
if downloadTerraform {
installer := &releases.ExactVersion{
InstallDir: options.CachePath,
Product: product.Terraform,
Expand All @@ -57,17 +100,6 @@ func Serve(ctx context.Context, options *ServeOptions) error {
return xerrors.Errorf("install terraform: %w", err)
}
options.BinaryPath = execPath
} else {
// If the "coder" binary is in the same directory as
// the "terraform" binary, "terraform" is returned.
//
// We must resolve the absolute path for other processes
// to execute this properly!
absoluteBinary, err := filepath.Abs(binaryPath)
if err != nil {
return xerrors.Errorf("absolute: %w", err)
}
options.BinaryPath = absoluteBinary
}
}
return provisionersdk.Serve(ctx, &server{
Expand Down