From 48b172aa860e4f06c545d243cb4698a4f4bed45b Mon Sep 17 00:00:00 2001 From: Paul Hinze Date: Tue, 26 Jan 2016 13:18:00 -0600 Subject: [PATCH] core: treat refs to unknown set resource attrs as unknown References to computed list-ish attributes (set, list, map) were being improperly resolved as an empty list `[]` during the plan phase (when the value of the reference is not yet known) instead of as an UnknownValue. A "diffs didn't match" failure in an AWS DirectoryServices test led to this discovery (and this commit fixes the failing test): https://travis-ci.org/hashicorp/terraform/jobs/104812951 Refs #2157 which has the original work to support computed list attributes at all. This is just a simple tweak to that work. /cc @radeksimko --- terraform/interpolate.go | 10 +++++++++ terraform/interpolate_test.go | 38 +++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/terraform/interpolate.go b/terraform/interpolate.go index 0ee61901cee1..461fdda5c1ba 100644 --- a/terraform/interpolate.go +++ b/terraform/interpolate.go @@ -519,6 +519,16 @@ func (i *Interpolater) interpolateListAttribute( log.Printf("[DEBUG] Interpolating computed list attribute %s (%s)", resourceID, attr) + // In Terraform's internal dotted representation of list-like attributes, the + // ".#" count field is marked as unknown to indicate "this whole list is + // unknown". We must honor that meaning here so computed references can be + // treated properly during the plan phase. + if attr == config.UnknownVariableValue { + return attr, nil + } + + // Otherwise we gather the values from the list-like attribute and return + // them. var members []string numberedListMember := regexp.MustCompile("^" + resourceID + "\\.[0-9]+$") for id, value := range attributes { diff --git a/terraform/interpolate_test.go b/terraform/interpolate_test.go index fbce848eaf64..6d2e9510585d 100644 --- a/terraform/interpolate_test.go +++ b/terraform/interpolate_test.go @@ -348,6 +348,44 @@ func TestInterpolator_resourceMultiAttributesWithResourceCount(t *testing.T) { }) } +func TestInterpolator_resourceMultiAttributesComputed(t *testing.T) { + lock := new(sync.RWMutex) + // The state would never be written with an UnknownVariableValue in it, but + // it can/does exist that way in memory during the plan phase. + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_route53_zone.yada": &ResourceState{ + Type: "aws_route53_zone", + Primary: &InstanceState{ + ID: "z-abc123", + Attributes: map[string]string{ + "name_servers.#": config.UnknownVariableValue, + }, + }, + }, + }, + }, + }, + } + i := &Interpolater{ + Module: testModule(t, "interpolate-multi-vars"), + StateLock: lock, + State: state, + } + + scope := &InterpolationScope{ + Path: rootModulePath, + } + + testInterpolate(t, i, scope, "aws_route53_zone.yada.name_servers", ast.Variable{ + Value: config.UnknownVariableValue, + Type: ast.TypeString, + }) +} + func getInterpolaterFixture(t *testing.T) *Interpolater { lock := new(sync.RWMutex) state := &State{