Skip to content
This repository has been archived by the owner on Apr 27, 2021. It is now read-only.

Reimplement Terraform funcs using tfexec #35

Merged
merged 2 commits into from
Sep 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ go 1.12

require (
github.com/hashicorp/go-getter v1.4.0
github.com/hashicorp/terraform-exec v0.3.0
github.com/hashicorp/terraform-exec v0.7.0
github.com/hashicorp/terraform-json v0.5.0
)
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,13 @@ github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCS
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/terraform-exec v0.3.0 h1:5WLBsnv9BoEUGlHJZETROZZxw+qO3/TFQEh6JMP2uaY=
github.com/hashicorp/terraform-exec v0.3.0/go.mod h1:yKWvMPtkTaHpeAmllw+1qdHZ7E5u+pAZ+x8e2jQF6gM=
github.com/hashicorp/terraform-exec v0.7.0 h1:mq3S/IqleQI5BM/NO//q4DZesI+Ie8fVkte9zpFX3qc=
github.com/hashicorp/terraform-exec v0.7.0/go.mod h1:fkVMi6NCKxBbnGaOgn5el3BnkZVatoFR+kfURdI+3YM=
github.com/hashicorp/terraform-json v0.5.0 h1:7TV3/F3y7QVSuN4r9BEXqnWqrAyeOtON8f0wvREtyzs=
github.com/hashicorp/terraform-json v0.5.0/go.mod h1:eAbqb4w0pSlRmdvl8fOyHAi/+8jnkVYN28gJkSJrLhU=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE=
Expand Down
6 changes: 3 additions & 3 deletions helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,9 @@ func (h *Helper) NewWorkingDir() (*WorkingDir, error) {
}

return &WorkingDir{
h: h,
baseArgs: []string{"-no-color"},
baseDir: dir,
h: h,
baseDir: dir,
terraformExec: h.terraformExec,
}, nil
}

Expand Down
101 changes: 30 additions & 71 deletions working_dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package tftest

import (
"bytes"
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"

"github.com/hashicorp/terraform-exec/tfexec"
tfjson "github.com/hashicorp/terraform-json"
)

Expand All @@ -26,6 +28,12 @@ type WorkingDir struct {
// configDir contains the singular config file generated for each test
configDir string

// tf is the instance of tfexec.Terraform used for running Terraform commands
tf *tfexec.Terraform

// terraformExec is a path to a terraform binary, inherited from Helper
terraformExec string

env map[string]string
}

Expand Down Expand Up @@ -81,7 +89,13 @@ func (wd *WorkingDir) SetConfig(cfg string) error {
return err
}

tf, err := tfexec.NewTerraform(wd.baseDir, wd.terraformExec)
if err != nil {
return err
}

wd.configDir = configDir
wd.tf = tf

// Changing configuration invalidates any saved plan.
err = wd.ClearPlan()
Expand Down Expand Up @@ -142,19 +156,14 @@ func (wd *WorkingDir) RequireClearPlan(t TestControl) {
}
}

func (wd *WorkingDir) init() error {
args := []string{"init", wd.configDir}
args = append(args, wd.baseArgs...)
return wd.runTerraform(nil, args...)
}

// Init runs "terraform init" for the given working directory, forcing Terraform
// to use the current version of the plugin under test.
func (wd *WorkingDir) Init() error {
if wd.configDir == "" {
return fmt.Errorf("must call SetConfig before Init")
}
return wd.init()

return wd.tf.Init(context.Background(), tfexec.Dir(wd.configDir))
}

// RequireInit is a variant of Init that will fail the test via the given
Expand All @@ -174,10 +183,7 @@ func (wd *WorkingDir) planFilename() string {
// CreatePlan runs "terraform plan" to create a saved plan file, which if successful
// will then be used for the next call to Apply.
func (wd *WorkingDir) CreatePlan() error {
args := []string{"plan", "-refresh=false"}
args = append(args, wd.baseArgs...)
args = append(args, "-out=tfplan", wd.configDir)
return wd.runTerraform(nil, args...)
return wd.tf.Plan(context.Background(), tfexec.Refresh(false), tfexec.Out("tfplan"), tfexec.Dir(wd.configDir))
}

// RequireCreatePlan is a variant of CreatePlan that will fail the test via
Expand All @@ -195,11 +201,9 @@ func (wd *WorkingDir) RequireCreatePlan(t TestControl) {
// this will apply the saved plan. Otherwise, it will implicitly create a new
// plan and apply it.
func (wd *WorkingDir) Apply() error {
args := []string{"apply", "-refresh=false"}
args = append(args, wd.baseArgs...)

args := []tfexec.ApplyOption{tfexec.Refresh(false)}
if wd.HasSavedPlan() {
args = append(args, "tfplan")
args = append(args, tfexec.DirOrPlan("tfplan"))
} else {
// we need to use a relative config dir here or we get an
// error about Terraform not having any configuration. See
Expand All @@ -209,11 +213,9 @@ func (wd *WorkingDir) Apply() error {
if err != nil {
return err
}
args = append(args, "-auto-approve")
args = append(args, configDir)
args = append(args, tfexec.DirOrPlan(configDir))
}

return wd.runTerraform(nil, args...)
return wd.tf.Apply(context.Background(), args...)
}

// RequireApply is a variant of Apply that will fail the test via
Expand All @@ -232,11 +234,7 @@ func (wd *WorkingDir) RequireApply(t TestControl) {
// If destroy fails then remote objects might still exist, and continue to
// exist after a particular test is concluded.
func (wd *WorkingDir) Destroy() error {
args := []string{"destroy", "-refresh=false"}
args = append(args, wd.baseArgs...)

args = append(args, "-auto-approve", wd.configDir)
return wd.runTerraform(nil, args...)
return wd.tf.Destroy(context.Background(), tfexec.Refresh(false), tfexec.Dir(wd.configDir))
}

// RequireDestroy is a variant of Destroy that will fail the test via
Expand Down Expand Up @@ -269,18 +267,7 @@ func (wd *WorkingDir) SavedPlan() (*tfjson.Plan, error) {
return nil, fmt.Errorf("there is no current saved plan")
}

var ret tfjson.Plan

args := []string{"show"}
args = append(args, wd.baseArgs...)
args = append(args, "-json", wd.planFilename())

err := wd.runTerraformJSON(&ret, args...)
if err != nil {
return nil, err
}

return &ret, nil
return wd.tf.ShowPlanFile(context.Background(), wd.planFilename())
}

// RequireSavedPlan is a variant of SavedPlan that will fail the test via
Expand All @@ -306,11 +293,9 @@ func (wd *WorkingDir) SavedPlanStdout() (string, error) {

var ret bytes.Buffer

args := []string{"show"}
args = append(args, wd.baseArgs...)
args = append(args, wd.planFilename())

err := wd.runTerraform(&ret, args...)
wd.tf.SetStdout(&ret)
defer wd.tf.SetStdout(ioutil.Discard)
_, err := wd.tf.ShowPlanFile(context.Background(), wd.planFilename())
if err != nil {
return "", err
}
Expand All @@ -334,18 +319,7 @@ func (wd *WorkingDir) RequireSavedPlanStdout(t TestControl) string {
//
// If the state cannot be read, State returns an error.
func (wd *WorkingDir) State() (*tfjson.State, error) {
var ret tfjson.State

args := []string{"show"}
args = append(args, wd.baseArgs...)
args = append(args, "-json")

err := wd.runTerraformJSON(&ret, args...)
if err != nil {
return nil, err
}

return &ret, nil
return wd.tf.Show(context.Background())
}

// RequireState is a variant of State that will fail the test via
Expand All @@ -362,10 +336,7 @@ func (wd *WorkingDir) RequireState(t TestControl) *tfjson.State {

// Import runs terraform import
func (wd *WorkingDir) Import(resource, id string) error {
args := []string{"import"}
args = append(args, wd.baseArgs...)
args = append(args, "-config="+wd.configDir, resource, id)
return wd.runTerraform(nil, args...)
return wd.tf.Import(context.Background(), resource, id, tfexec.Config(wd.configDir))
}

// RequireImport is a variant of Import that will fail the test via
Expand All @@ -380,11 +351,7 @@ func (wd *WorkingDir) RequireImport(t TestControl, resource, id string) {

// Refresh runs terraform refresh
func (wd *WorkingDir) Refresh() error {
args := []string{"refresh"}
args = append(args, wd.baseArgs...)
args = append(args, "-state="+filepath.Join(wd.baseDir, "terraform.tfstate"))
args = append(args, wd.configDir)
return wd.runTerraform(nil, args...)
return wd.tf.Refresh(context.Background(), tfexec.State(filepath.Join(wd.baseDir, "terraform.tfstate")), tfexec.Dir(wd.configDir))
}

// RequireRefresh is a variant of Refresh that will fail the test via
Expand All @@ -401,15 +368,7 @@ func (wd *WorkingDir) RequireRefresh(t TestControl) {
//
// If the schemas cannot be read, Schemas returns an error.
func (wd *WorkingDir) Schemas() (*tfjson.ProviderSchemas, error) {
args := []string{"providers", wd.configDir, "schema"}

var ret tfjson.ProviderSchemas
err := wd.runTerraformJSON(&ret, args...)
if err != nil {
return nil, err
}

return &ret, nil
return wd.tf.ProvidersSchema(context.Background())
}

// RequireSchemas is a variant of Schemas that will fail the test via
Expand Down