diff --git a/CHANGELOG.md b/CHANGELOG.md index d9e2e15ce4..034f476a06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ BUG FIXES: * core: Fix issue where some JSON structures didn't map properly into Terraform structures. [GH-177] * core: Resources with only `file()` calls will interpolate. [GH-159] + * command/apply: "tfvars" file no longer interferes with plan apply. [GH-153] * providers/aws: Fix issues around failing to read EIPs. [GH-122] * providers/aws: Autoscaling groups now register and export load balancers. [GH-207] diff --git a/command/apply_test.go b/command/apply_test.go index 9a5edcf604..5cd7b7da02 100644 --- a/command/apply_test.go +++ b/command/apply_test.go @@ -283,6 +283,63 @@ func TestApply_plan(t *testing.T) { } } +func TestApply_planWithVarFile(t *testing.T) { + varFileDir := testTempDir(t) + varFilePath := filepath.Join(varFileDir, "terraform.tfvars") + if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil { + t.Fatalf("err: %s", err) + } + + planPath := testPlanFile(t, &terraform.Plan{ + Config: new(config.Config), + }) + statePath := testTempFile(t) + + cwd, err := os.Getwd() + if err != nil { + t.Fatalf("err: %s", err) + } + if err := os.Chdir(varFileDir); err != nil { + t.Fatalf("err: %s", err) + } + defer os.Chdir(cwd) + + p := testProvider() + ui := new(cli.MockUi) + c := &ApplyCommand{ + Meta: Meta{ + ContextOpts: testCtxConfig(p), + Ui: ui, + }, + } + + args := []string{ + "-state", statePath, + planPath, + } + if code := c.Run(args); code != 0 { + t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) + } + + if _, err := os.Stat(statePath); err != nil { + t.Fatalf("err: %s", err) + } + + f, err := os.Open(statePath) + if err != nil { + t.Fatalf("err: %s", err) + } + defer f.Close() + + state, err := terraform.ReadState(f) + if err != nil { + t.Fatalf("err: %s", err) + } + if state == nil { + t.Fatal("state should not be nil") + } +} + func TestApply_planVars(t *testing.T) { planPath := testPlanFile(t, &terraform.Plan{ Config: new(config.Config), diff --git a/command/meta.go b/command/meta.go index aaf00d7dd0..1b83e6da91 100644 --- a/command/meta.go +++ b/command/meta.go @@ -3,6 +3,7 @@ package command import ( "flag" "fmt" + "math/rand" "os" "github.com/hashicorp/terraform/config" @@ -25,7 +26,9 @@ type Meta struct { extraHooks []terraform.Hook // Variables for the context (private) - variables map[string]string + autoKey string + autoVariables map[string]string + variables map[string]string color bool oldUi cli.Ui @@ -109,16 +112,17 @@ func (m *Meta) contextOpts() *terraform.ContextOpts { copy(opts.Hooks[1:], m.ContextOpts.Hooks) copy(opts.Hooks[len(m.ContextOpts.Hooks)+1:], m.extraHooks) - if len(m.variables) > 0 { - vs := make(map[string]string) - for k, v := range opts.Variables { - vs[k] = v - } - for k, v := range m.variables { - vs[k] = v - } - opts.Variables = vs + vs := make(map[string]string) + for k, v := range opts.Variables { + vs[k] = v } + for k, v := range m.autoVariables { + vs[k] = v + } + for k, v := range m.variables { + vs[k] = v + } + opts.Variables = vs return &opts } @@ -128,6 +132,11 @@ func (m *Meta) flagSet(n string) *flag.FlagSet { f := flag.NewFlagSet(n, flag.ContinueOnError) f.Var((*FlagVar)(&m.variables), "var", "variables") f.Var((*FlagVarFile)(&m.variables), "var-file", "variable file") + + if m.autoKey != "" { + f.Var((*FlagVarFile)(&m.autoVariables), m.autoKey, "variable file") + } + return f } @@ -163,11 +172,13 @@ func (m *Meta) process(args []string, vars bool) []string { // If we support vars and the default var file exists, add it to // the args... + m.autoKey = "" if vars { if _, err := os.Stat(DefaultVarsFilename); err == nil { + m.autoKey = fmt.Sprintf("var-file-%d", rand.Int()) args = append(args, "", "") copy(args[2:], args[0:]) - args[0] = "-var-file" + args[0] = "-" + m.autoKey args[1] = DefaultVarsFilename } }