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

Commit

Permalink
Merge pull request #35 from hashicorp/tfexec
Browse files Browse the repository at this point in the history
Reimplement Terraform funcs using tfexec
  • Loading branch information
kmoe authored Sep 1, 2020
2 parents 16c796e + aef0b05 commit 6b97cd1
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 77 deletions.
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

0 comments on commit 6b97cd1

Please sign in to comment.