From 99fbb91ba255c8f5d92db489c0ed92bd11c6691e Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 19 Jan 2016 11:28:45 -0800 Subject: [PATCH] config: validate lifecycle keys [GH-4413] --- config/loader_hcl.go | 36 ++++++++++++++++++++++ config/loader_test.go | 9 ++++++ config/test-fixtures/lifecycle_cbd_typo.tf | 5 +++ 3 files changed, 50 insertions(+) create mode 100644 config/test-fixtures/lifecycle_cbd_typo.tf diff --git a/config/loader_hcl.go b/config/loader_hcl.go index 59fe81795..400f394c5 100644 --- a/config/loader_hcl.go +++ b/config/loader_hcl.go @@ -4,6 +4,7 @@ import ( "fmt" "io/ioutil" + "github.com/hashicorp/go-multierror" "github.com/hashicorp/hcl" "github.com/hashicorp/hcl/hcl/ast" "github.com/mitchellh/mapstructure" @@ -524,6 +525,13 @@ func loadResourcesHcl(list *ast.ObjectList) ([]*Resource, error) { // destroying the existing instance var lifecycle ResourceLifecycle if o := listVal.Filter("lifecycle"); len(o.Items) > 0 { + // Check for invalid keys + valid := []string{"create_before_destroy", "ignore_changes", "prevent_destroy"} + if err := checkHCLKeys(o.Items[0].Val, valid); err != nil { + return nil, multierror.Prefix(err, fmt.Sprintf( + "%s[%s]:", t, k)) + } + var raw map[string]interface{} if err = hcl.DecodeObject(&raw, o.Items[0].Val); err != nil { return nil, fmt.Errorf( @@ -645,3 +653,31 @@ func hclObjectMap(os *hclobj.Object) map[string]ast.ListNode { return objects } */ + +func checkHCLKeys(node ast.Node, valid []string) error { + var list *ast.ObjectList + switch n := node.(type) { + case *ast.ObjectList: + list = n + case *ast.ObjectType: + list = n.List + default: + return fmt.Errorf("cannot check HCL keys of type %T", n) + } + + validMap := make(map[string]struct{}, len(valid)) + for _, v := range valid { + validMap[v] = struct{}{} + } + + var result error + for _, item := range list.Items { + key := item.Keys[0].Token.Value().(string) + if _, ok := validMap[key]; !ok { + result = multierror.Append(result, fmt.Errorf( + "invalid key: %s", key)) + } + } + + return result +} diff --git a/config/loader_test.go b/config/loader_test.go index 6dbcfbede..bfe21cfb2 100644 --- a/config/loader_test.go +++ b/config/loader_test.go @@ -45,6 +45,15 @@ func TestLoadFile_badType(t *testing.T) { } } +func TestLoadFile_lifecycleKeyCheck(t *testing.T) { + _, err := LoadFile(filepath.Join(fixtureDir, "lifecycle_cbd_typo.tf")) + if err == nil { + t.Fatal("should have error") + } + + t.Logf("err: %s", err) +} + func TestLoadFile_resourceArityMistake(t *testing.T) { _, err := LoadFile(filepath.Join(fixtureDir, "resource-arity-mistake.tf")) if err == nil { diff --git a/config/test-fixtures/lifecycle_cbd_typo.tf b/config/test-fixtures/lifecycle_cbd_typo.tf new file mode 100644 index 000000000..8997492ab --- /dev/null +++ b/config/test-fixtures/lifecycle_cbd_typo.tf @@ -0,0 +1,5 @@ +resource "foo" "bar" { + lifecycle { + create_before_destroyy = false + } +}