Merge pull request #17127 from hashicorp/jbardin/ignore_changes

don't ignore partial containers in diffs
This commit is contained in:
James Bardin 2018-01-19 16:08:18 -05:00 committed by GitHub
commit d29994e247
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 90 additions and 51 deletions

View File

@ -396,11 +396,6 @@ type ResourceAttrDiff struct {
Type DiffAttrType Type DiffAttrType
} }
// Modified returns the inequality of Old and New for this attr
func (d *ResourceAttrDiff) Modified() bool {
return d.Old != d.New
}
// Empty returns true if the diff for this attr is neutral // Empty returns true if the diff for this attr is neutral
func (d *ResourceAttrDiff) Empty() bool { func (d *ResourceAttrDiff) Empty() bool {
return d.Old == d.New && !d.NewComputed && !d.NewRemoved return d.Old == d.New && !d.NewComputed && !d.NewRemoved

View File

@ -256,13 +256,15 @@ func (n *EvalDiff) processIgnoreChanges(diff *InstanceDiff) error {
containers := groupContainers(diff) containers := groupContainers(diff)
keep := map[string]bool{} keep := map[string]bool{}
for _, v := range containers { for _, v := range containers {
if v.keepDiff() { if v.keepDiff(ignorableAttrKeys) {
// At least one key has changes, so list all the sibling keys // At least one key has changes, so list all the sibling keys
// to keep in the diff if any values have changed // to keep in the diff
for k := range v { for k := range v {
if v[k].Modified() {
keep[k] = true keep[k] = true
} // this key may have been added by the user to ignore, but
// if it's a subkey in a container, we need to un-ignore it
// to keep the complete containter.
delete(ignorableAttrKeys, k)
} }
} }
} }
@ -294,10 +296,17 @@ func (n *EvalDiff) processIgnoreChanges(diff *InstanceDiff) error {
// a group of key-*ResourceAttrDiff pairs from the same flatmapped container // a group of key-*ResourceAttrDiff pairs from the same flatmapped container
type flatAttrDiff map[string]*ResourceAttrDiff type flatAttrDiff map[string]*ResourceAttrDiff
// we need to keep all keys if any of them have a diff // we need to keep all keys if any of them have a diff that's not ignored
func (f flatAttrDiff) keepDiff() bool { func (f flatAttrDiff) keepDiff(ignoreChanges map[string]bool) bool {
for _, v := range f { for k, v := range f {
if !v.Empty() && !v.NewComputed { ignore := false
for attr := range ignoreChanges {
if strings.HasPrefix(k, attr) {
ignore = true
}
}
if !v.Empty() && !v.NewComputed && !ignore {
return true return true
} }
} }

View File

@ -1,6 +1,7 @@
package terraform package terraform
import ( import (
"fmt"
"reflect" "reflect"
"testing" "testing"
@ -79,7 +80,7 @@ func TestEvalFilterDiff(t *testing.T) {
} }
} }
func TestProcessIgnoreChangesOnResourceIgnoredWithRequiresNew(t *testing.T) { func TestProcessIgnoreChanges(t *testing.T) {
var evalDiff *EvalDiff var evalDiff *EvalDiff
var instanceDiff *InstanceDiff var instanceDiff *InstanceDiff
@ -94,53 +95,84 @@ func TestProcessIgnoreChangesOnResourceIgnoredWithRequiresNew(t *testing.T) {
&InstanceDiff{ &InstanceDiff{
Destroy: true, Destroy: true,
Attributes: map[string]*ResourceAttrDiff{ Attributes: map[string]*ResourceAttrDiff{
"resource.%": {
Old: "3",
New: "3",
},
"resource.changed": { "resource.changed": {
RequiresNew: true, RequiresNew: true,
Type: DiffAttrInput, Type: DiffAttrInput,
Old: "old", Old: "old",
New: "new", New: "new",
}, },
"resource.unchanged": { "resource.maybe": {
Old: "unchanged", Old: "",
New: newAttribute, New: newAttribute,
}, },
"resource.same": {
Old: "same",
New: "same",
},
}, },
} }
} }
evalDiff, instanceDiff = testDiffs([]string{"resource.changed"}, "unchanged") for i, tc := range []struct {
ignore []string
newAttr string
attrDiffs int
}{
// attr diffs should be all (4), or nothing
{
ignore: []string{"resource.changed"},
attrDiffs: 0,
},
{
ignore: []string{"resource.changed"},
newAttr: "new",
attrDiffs: 4,
},
{
attrDiffs: 4,
},
{
ignore: []string{"resource.maybe"},
newAttr: "new",
attrDiffs: 4,
},
{
newAttr: "new",
attrDiffs: 4,
},
{
ignore: []string{"resource"},
newAttr: "new",
attrDiffs: 0,
},
// extra ignored values shouldn't effect the diff
{
ignore: []string{"resource.missing", "resource.maybe"},
newAttr: "new",
attrDiffs: 4,
},
// this isn't useful, but make sure it doesn't break
{
ignore: []string{"resource.%"},
attrDiffs: 4,
},
} {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
evalDiff, instanceDiff = testDiffs(tc.ignore, tc.newAttr)
err := evalDiff.processIgnoreChanges(instanceDiff) err := evalDiff.processIgnoreChanges(instanceDiff)
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
if len(instanceDiff.Attributes) > 0 { if len(instanceDiff.Attributes) != tc.attrDiffs {
t.Fatalf("Expected all resources to be ignored, found %d", len(instanceDiff.Attributes)) t.Errorf("expected %d diffs, found %d", tc.attrDiffs, len(instanceDiff.Attributes))
} for k, attr := range instanceDiff.Attributes {
fmt.Printf(" %s:%#v\n", k, attr)
evalDiff, instanceDiff = testDiffs([]string{}, "unchanged") }
err = evalDiff.processIgnoreChanges(instanceDiff) }
if err != nil { })
t.Fatalf("err: %s", err)
}
if len(instanceDiff.Attributes) != 2 {
t.Fatalf("Expected 2 resources to be found, found %d", len(instanceDiff.Attributes))
}
evalDiff, instanceDiff = testDiffs([]string{"resource.changed"}, "changed")
err = evalDiff.processIgnoreChanges(instanceDiff)
if err != nil {
t.Fatalf("err: %s", err)
}
if len(instanceDiff.Attributes) != 1 {
t.Fatalf("Expected 1 resource to be found, found %d", len(instanceDiff.Attributes))
}
evalDiff, instanceDiff = testDiffs([]string{}, "changed")
err = evalDiff.processIgnoreChanges(instanceDiff)
if err != nil {
t.Fatalf("err: %s", err)
}
if len(instanceDiff.Attributes) != 2 {
t.Fatalf("Expected 2 resource to be found, found %d", len(instanceDiff.Attributes))
} }
} }

View File

@ -1675,7 +1675,10 @@ aws_instance.foo:
const testTFPlanDiffIgnoreChangesWithFlatmaps = ` const testTFPlanDiffIgnoreChangesWithFlatmaps = `
UPDATE: aws_instance.foo UPDATE: aws_instance.foo
lst.#: "1" => "2" lst.#: "1" => "2"
lst.0: "j" => "j"
lst.1: "" => "k" lst.1: "" => "k"
set.#: "1" => "1"
set.0.a: "1" => "1"
set.0.b: "" => "2" set.0.b: "" => "2"
type: "" => "aws_instance" type: "" => "aws_instance"
` `