diff --git a/helper/schema/field_reader_config_test.go b/helper/schema/field_reader_config_test.go index 01cc1d703..8ca0a2fbe 100644 --- a/helper/schema/field_reader_config_test.go +++ b/helper/schema/field_reader_config_test.go @@ -1,11 +1,14 @@ package schema import ( + "bytes" + "fmt" "reflect" "testing" "github.com/hashicorp/hil/ast" "github.com/hashicorp/terraform/config" + "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/terraform" ) @@ -391,6 +394,138 @@ func TestConfigFieldReader_ComputedSet(t *testing.T) { } } +func TestConfigFieldReader_computedComplexSet(t *testing.T) { + hashfunc := func(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["vhd_uri"].(string))) + return hashcode.String(buf.String()) + } + + schema := map[string]*Schema{ + "set": &Schema{ + Type: TypeSet, + Elem: &Resource{ + Schema: map[string]*Schema{ + "name": { + Type: TypeString, + Required: true, + }, + + "vhd_uri": { + Type: TypeString, + Required: true, + }, + }, + }, + Set: hashfunc, + }, + } + + cases := map[string]struct { + Addr []string + Result FieldReadResult + Config *terraform.ResourceConfig + Err bool + }{ + "set, normal": { + []string{"set"}, + FieldReadResult{ + Value: map[string]interface{}{ + "532860136": map[string]interface{}{ + "name": "myosdisk1", + "vhd_uri": "bar", + }, + }, + Exists: true, + Computed: false, + }, + testConfig(t, map[string]interface{}{ + "set": []interface{}{ + map[string]interface{}{ + "name": "myosdisk1", + "vhd_uri": "bar", + }, + }, + }), + false, + }, + + "set, computed element": { + []string{"set"}, + FieldReadResult{ + Value: map[string]interface{}{ + "~3596295623": map[string]interface{}{ + "name": "myosdisk1", + "vhd_uri": "${var.foo}/bar", + }, + }, + Exists: true, + Computed: false, + }, + testConfigInterpolate(t, map[string]interface{}{ + "set": []interface{}{ + map[string]interface{}{ + "name": "myosdisk1", + "vhd_uri": "${var.foo}/bar", + }, + }, + }, map[string]ast.Variable{ + "var.foo": ast.Variable{ + Value: config.UnknownVariableValue, + Type: ast.TypeUnknown, + }, + }), + false, + }, + + "set, computed element single": { + []string{"set", "~3596295623", "vhd_uri"}, + FieldReadResult{ + Value: "${var.foo}/bar", + Exists: true, + Computed: true, + }, + testConfigInterpolate(t, map[string]interface{}{ + "set": []interface{}{ + map[string]interface{}{ + "name": "myosdisk1", + "vhd_uri": "${var.foo}/bar", + }, + }, + }, map[string]ast.Variable{ + "var.foo": ast.Variable{ + Value: config.UnknownVariableValue, + Type: ast.TypeUnknown, + }, + }), + false, + }, + } + + for name, tc := range cases { + r := &ConfigFieldReader{ + Schema: schema, + Config: tc.Config, + } + out, err := r.ReadField(tc.Addr) + if err != nil != tc.Err { + t.Fatalf("%s: err: %s", name, err) + } + if s, ok := out.Value.(*Set); ok { + // If it is a set, convert to the raw map + out.Value = s.m + if len(s.m) == 0 { + out.Value = nil + } + } + if !reflect.DeepEqual(tc.Result, out) { + t.Fatalf("%s: bad: %#v", name, out) + } + } +} + func testConfig( t *testing.T, raw map[string]interface{}) *terraform.ResourceConfig { return testConfigInterpolate(t, raw, nil) diff --git a/terraform/interpolate.go b/terraform/interpolate.go index 2bc74994f..3fb0b66a7 100644 --- a/terraform/interpolate.go +++ b/terraform/interpolate.go @@ -404,7 +404,8 @@ func (i *Interpolater) computeResourceVariable( } if attr, ok := r.Primary.Attributes[v.Field]; ok { - return &ast.Variable{Type: ast.TypeString, Value: attr}, nil + v, err := hil.InterfaceToVariable(attr) + return &v, err } // computed list or map attribute diff --git a/terraform/interpolate_test.go b/terraform/interpolate_test.go index 9b0925908..4eaf882bc 100644 --- a/terraform/interpolate_test.go +++ b/terraform/interpolate_test.go @@ -569,6 +569,44 @@ func TestInterpolator_resourceMultiAttributesComputed(t *testing.T) { }) } +func TestInterpolator_resourceAttributeComputed(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{ + "id": 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.id", ast.Variable{ + Value: config.UnknownVariableValue, + Type: ast.TypeUnknown, + }) +} + func TestInterpolater_selfVarWithoutResource(t *testing.T) { i := &Interpolater{} diff --git a/vendor/github.com/hashicorp/hil/convert.go b/vendor/github.com/hashicorp/hil/convert.go index 983b66baf..f2024d01c 100644 --- a/vendor/github.com/hashicorp/hil/convert.go +++ b/vendor/github.com/hashicorp/hil/convert.go @@ -55,7 +55,7 @@ func InterfaceToVariable(input interface{}) (ast.Variable, error) { if err := hilMapstructureWeakDecode(input, &stringVal); err == nil { // Special case the unknown value to turn into "unknown" if stringVal == UnknownValue { - return ast.Variable{Type: ast.TypeUnknown}, nil + return ast.Variable{Value: UnknownValue, Type: ast.TypeUnknown}, nil } // Otherwise return the string value diff --git a/vendor/vendor.json b/vendor/vendor.json index 3d4d0f28a..3758fa418 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1412,10 +1412,10 @@ "revisionTime": "2016-11-09T22:51:35Z" }, { - "checksumSHA1": "mZhRldYjh9MAXzdi3zihMX0A/JU=", + "checksumSHA1": "PjLBj8sicHOz2ZzuaMTPZ09OuFs=", "path": "github.com/hashicorp/hil", - "revision": "ce4ab742a9dd2bb6e55050337333b2c56666e5a0", - "revisionTime": "2016-10-27T15:25:34Z" + "revision": "a69e0a85dd050184c00f6080fce138f2dadb1a4c", + "revisionTime": "2016-11-11T01:09:07Z" }, { "checksumSHA1": "FFroNUb6Nn6xUQJMsVDTb4Cqzo4=", @@ -1880,7 +1880,6 @@ }, { "checksumSHA1": "DVXnx4zyb0wkeIdIRjwjvR7Dslo=", - "origin": "github.com/hashicorp/terraform/vendor/github.com/mitchellh/go-ps", "path": "github.com/mitchellh/go-ps", "revision": "e2d21980687ce16e58469d98dcee92d27fbbd7fb", "revisionTime": "2016-08-22T16:54:47Z"