From 30ff37f33525cc7ec218aef0adc8622271534ac6 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Fri, 27 Jul 2018 14:26:49 -0400 Subject: [PATCH] change PathFromFlatmapKey to RequiresReplace Rather than try and make a generalized path function here, what we really need in a function to generate the paths needed for RequiresReplace. This needs to take into account that sets elements don't need to be indexed themselves, and changes to collection index values aren't needed. --- config/hcl2shim/paths.go | 44 ++++++++++++++++++++++++++++++++--- config/hcl2shim/paths_test.go | 2 +- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/config/hcl2shim/paths.go b/config/hcl2shim/paths.go index 7c67132496..c80b12ba06 100644 --- a/config/hcl2shim/paths.go +++ b/config/hcl2shim/paths.go @@ -2,21 +2,59 @@ package hcl2shim import ( "fmt" + "reflect" "strconv" "strings" "github.com/zclconf/go-cty/cty" ) -// PathFromFlatmapKey takes a key from a flatmap along with the cty.Type +// RequiresReplace takes a list of flatmapped paths from a +// InstanceDiff.Attributes along with the corresponding cty.Type, and returns +// the list of the cty.Paths that are flagged as causing the resource +// replacement (RequiresNew). +// This will filter out paths that inadvertently refer to flatmapped indexes +// (e.g. "#", "%"), and will return any changes within a set as the path to the +// set itself. +func RequiresReplace(attrs []string, ty cty.Type) ([]cty.Path, error) { + var paths []cty.Path + + for _, attr := range attrs { + p, err := requiresReplacePath(attr, ty) + if err != nil { + return nil, err + } + + paths = append(paths, p) + } + + // There may be redundant paths due to set elements or index attributes + // Do some ugly n^2 filtering, but these are always fairly small sets. + + for i := 0; i < len(paths)-1; i++ { + for j := i + 1; j < len(paths); j++ { + if reflect.DeepEqual(paths[i], paths[j]) { + // swap the tail and slice it off + paths[j], paths[len(paths)-1] = paths[len(paths)-1], paths[j] + paths = paths[:len(paths)-1] + j-- + } + } + } + + return paths, nil +} + +// requiresReplacePath takes a key from a flatmap along with the cty.Type // describing the structure, and returns the cty.Path that would be used to // reference the nested value in the data structure. -func PathFromFlatmapKey(k string, ty cty.Type) (cty.Path, error) { +// This is used specifically to record the RequiresReplace attributes from a ResourceInstanceDiff. +func requiresReplacePath(k string, ty cty.Type) (cty.Path, error) { if k == "" { return nil, nil } if !ty.IsObjectType() { - panic(fmt.Sprintf("PathFromFlatmapKey called on %#v", ty)) + panic(fmt.Sprintf("RequiresReplacePathFromKey called on %#v", ty)) } path, err := pathFromFlatmapKeyObject(k, ty.AttributeTypes()) diff --git a/config/hcl2shim/paths_test.go b/config/hcl2shim/paths_test.go index e63f78adc0..167b57a643 100644 --- a/config/hcl2shim/paths_test.go +++ b/config/hcl2shim/paths_test.go @@ -143,7 +143,7 @@ func TestPathFromFlatmap(t *testing.T) { for _, test := range tests { t.Run(fmt.Sprintf("%s as %#v", test.Flatmap, test.Type), func(t *testing.T) { - got, err := PathFromFlatmapKey(test.Flatmap, test.Type) + got, err := requiresReplacePath(test.Flatmap, test.Type) if test.WantErr != "" { if err == nil {