From 2820845f8c3b21cb35666c29fa276da535ab99dd Mon Sep 17 00:00:00 2001 From: James Bardin Date: Tue, 17 Jan 2017 15:41:57 -0500 Subject: [PATCH] Remove 0 counts from flatmap during MergeDiff When a InstanceState is merged with an InstanceDiff, any maps arrays or sets that no longer exist are shown as empty with a count of 0. If these are left in the flatmap structure, they will cause errors during expansion because their existing in the map affects the counts for parent structures. --- terraform/state.go | 20 +++++++++++++++++ terraform/state_test.go | 50 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/terraform/state.go b/terraform/state.go index 472fac0d5..f05ca4773 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -9,6 +9,7 @@ import ( "io/ioutil" "log" "reflect" + "regexp" "sort" "strconv" "strings" @@ -1664,6 +1665,25 @@ func (s *InstanceState) MergeDiff(d *InstanceDiff) *InstanceState { } } + // Remove any now empty array, maps or sets because a parent structure + // won't include these entries in the count value. + isCount := regexp.MustCompile(`\.[%#]$`).MatchString + for k, v := range result.Attributes { + if isCount(k) && v == "0" { + delete(result.Attributes, k) + + // Sanity check for invalid structures. + // If we removed the primary count key, there should have been no + // other keys left with this prefix. + base := k[:len(k)-2] + for k, _ := range result.Attributes { + if strings.HasPrefix(k, base) { + panic(fmt.Sprintf("empty structure %q has entry %q", base, k)) + } + } + } + } + return result } diff --git a/terraform/state_test.go b/terraform/state_test.go index 507c0c4a7..c2591e633 100644 --- a/terraform/state_test.go +++ b/terraform/state_test.go @@ -1392,6 +1392,56 @@ func TestInstanceState_MergeDiff(t *testing.T) { } } +// Make sure we don't leave empty maps or arrays in the flatmapped Attributes, +// since those may affect the counts of a parent structure. +func TestInstanceState_MergeDiffRemoveCounts(t *testing.T) { + is := InstanceState{ + ID: "foo", + Attributes: map[string]string{ + "all.#": "3", + "all.1111": "x", + "all.1234.#": "1", + "all.1234.0": "a", + "all.5678.%": "1", + "all.5678.key": "val", + }, + } + + diff := &InstanceDiff{ + Attributes: map[string]*ResourceAttrDiff{ + "all.#": &ResourceAttrDiff{ + Old: "3", + New: "1", + }, + "all.1234.0": &ResourceAttrDiff{ + NewRemoved: true, + }, + "all.1234.#": &ResourceAttrDiff{ + Old: "1", + New: "0", + }, + "all.5678.key": &ResourceAttrDiff{ + NewRemoved: true, + }, + "all.5678.%": &ResourceAttrDiff{ + Old: "1", + New: "0", + }, + }, + } + + is2 := is.MergeDiff(diff) + + expected := map[string]string{ + "all.#": "1", + "all.1111": "x", + } + + if !reflect.DeepEqual(expected, is2.Attributes) { + t.Fatalf("bad: %#v", is2.Attributes) + } +} + func TestInstanceState_MergeDiff_nil(t *testing.T) { var is *InstanceState