From 7b4119027ad68bb0ce9920472acde72caed67814 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 18 Jul 2014 14:00:40 -0700 Subject: [PATCH] command: -var-file works --- command/apply_test.go | 47 ++++++++++++++++++++++++++++++++++++ command/flag_var.go | 41 +++++++++++++++++++++++++++++++- command/flag_var_test.go | 51 ++++++++++++++++++++++++++++++++++++++++ command/plan_test.go | 43 +++++++++++++++++++++++++++++++++ command/refresh_test.go | 46 ++++++++++++++++++++++++++++++++++++ 5 files changed, 227 insertions(+), 1 deletion(-) diff --git a/command/apply_test.go b/command/apply_test.go index db1ee949a9..3d73b61408 100644 --- a/command/apply_test.go +++ b/command/apply_test.go @@ -504,3 +504,50 @@ func TestApply_vars(t *testing.T) { t.Fatal("didn't work") } } + +func TestApply_varFile(t *testing.T) { + varFilePath := testTempFile(t) + if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil { + t.Fatalf("err: %s", err) + } + + statePath := testTempFile(t) + + p := testProvider() + ui := new(cli.MockUi) + c := &ApplyCommand{ + Meta: Meta{ + ContextOpts: testCtxConfig(p), + Ui: ui, + }, + } + + actual := "" + p.DiffFn = func( + s *terraform.ResourceState, + c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + if v, ok := c.Config["value"]; ok { + actual = v.(string) + } + + return nil, nil + } + + args := []string{ + "-init", + "-var-file", varFilePath, + "-state", statePath, + testFixturePath("apply-vars"), + } + if code := c.Run(args); code != 0 { + t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) + } + + if actual != "bar" { + t.Fatal("didn't work") + } +} + +const applyVarFile = ` +foo = "bar" +` diff --git a/command/flag_var.go b/command/flag_var.go index 8d54f20c4a..41450366fa 100644 --- a/command/flag_var.go +++ b/command/flag_var.go @@ -3,6 +3,8 @@ package command import ( "fmt" "strings" + + "github.com/mitchellh/go-libucl" ) // FlagVar is a flag.Value implementation for parsing user variables @@ -37,6 +39,43 @@ func (v *FlagVarFile) String() string { } func (v *FlagVarFile) Set(raw string) error { - // TODO + vs, err := loadVarFile(raw) + if err != nil { + return err + } + + if *v == nil { + *v = make(map[string]string) + } + + for key, value := range vs { + (*v)[key] = value + } + return nil } + +const libuclParseFlags = libucl.ParserKeyLowercase + +func loadVarFile(path string) (map[string]string, error) { + var obj *libucl.Object + + parser := libucl.NewParser(libuclParseFlags) + err := parser.AddFile(path) + if err == nil { + obj = parser.Object() + defer obj.Close() + } + defer parser.Close() + + if err != nil { + return nil, err + } + + var result map[string]string + if err := obj.Decode(&result); err != nil { + return nil, err + } + + return result, nil +} diff --git a/command/flag_var_test.go b/command/flag_var_test.go index 1177b325c6..5591797d78 100644 --- a/command/flag_var_test.go +++ b/command/flag_var_test.go @@ -2,6 +2,7 @@ package command import ( "flag" + "io/ioutil" "reflect" "testing" ) @@ -54,3 +55,53 @@ func TestFlagVar(t *testing.T) { } } } + +func TestFlagVarFile_impl(t *testing.T) { + var _ flag.Value = new(FlagVarFile) +} + +func TestFlagVarFile(t *testing.T) { + inputLibucl := ` +foo = "bar" +` + + inputJson := `{ + "foo": "bar"}` + + cases := []struct { + Input string + Output map[string]string + Error bool + }{ + { + inputLibucl, + map[string]string{"foo": "bar"}, + false, + }, + + { + inputJson, + map[string]string{"foo": "bar"}, + false, + }, + } + + path := testTempFile(t) + + for _, tc := range cases { + if err := ioutil.WriteFile(path, []byte(tc.Input), 0644); err != nil { + t.Fatalf("err: %s", err) + } + + f := new(FlagVarFile) + err := f.Set(path) + if (err != nil) != tc.Error { + t.Fatalf("bad error. Input: %#v", tc.Input) + } + + actual := map[string]string(*f) + if !reflect.DeepEqual(actual, tc.Output) { + t.Fatalf("bad: %#v", actual) + } + } +} diff --git a/command/plan_test.go b/command/plan_test.go index 5a5778736c..7a2f171d98 100644 --- a/command/plan_test.go +++ b/command/plan_test.go @@ -315,3 +315,46 @@ func TestPlan_vars(t *testing.T) { t.Fatal("didn't work") } } + +func TestPlan_varFile(t *testing.T) { + varFilePath := testTempFile(t) + if err := ioutil.WriteFile(varFilePath, []byte(planVarFile), 0644); err != nil { + t.Fatalf("err: %s", err) + } + + p := testProvider() + ui := new(cli.MockUi) + c := &PlanCommand{ + Meta: Meta{ + ContextOpts: testCtxConfig(p), + Ui: ui, + }, + } + + actual := "" + p.DiffFn = func( + s *terraform.ResourceState, + c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) { + if v, ok := c.Config["value"]; ok { + actual = v.(string) + } + + return nil, nil + } + + args := []string{ + "-var-file", varFilePath, + testFixturePath("plan-vars"), + } + if code := c.Run(args); code != 0 { + t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) + } + + if actual != "bar" { + t.Fatal("didn't work") + } +} + +const planVarFile = ` +foo = "bar" +` diff --git a/command/refresh_test.go b/command/refresh_test.go index 0f583cfef8..9525c68a99 100644 --- a/command/refresh_test.go +++ b/command/refresh_test.go @@ -333,3 +333,49 @@ func TestRefresh_var(t *testing.T) { t.Fatalf("bad: %#v", p.ConfigureConfig.Config) } } + +func TestRefresh_varFile(t *testing.T) { + state := &terraform.State{ + Resources: map[string]*terraform.ResourceState{ + "test_instance.foo": &terraform.ResourceState{ + ID: "bar", + Type: "test_instance", + }, + }, + } + statePath := testStateFile(t, state) + + p := testProvider() + ui := new(cli.MockUi) + c := &RefreshCommand{ + Meta: Meta{ + ContextOpts: testCtxConfig(p), + Ui: ui, + }, + } + + varFilePath := testTempFile(t) + if err := ioutil.WriteFile(varFilePath, []byte(refreshVarFile), 0644); err != nil { + t.Fatalf("err: %s", err) + } + + args := []string{ + "-var-file", varFilePath, + "-state", statePath, + testFixturePath("refresh-var"), + } + if code := c.Run(args); code != 0 { + t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) + } + + if !p.ConfigureCalled { + t.Fatal("configure should be called") + } + if p.ConfigureConfig.Config["value"].(string) != "bar" { + t.Fatalf("bad: %#v", p.ConfigureConfig.Config) + } +} + +const refreshVarFile = ` +foo = "bar" +`