From fa934d96d094e34a36ba728ded137dc17be932dd Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 21 Apr 2015 22:07:52 +0200 Subject: [PATCH] helper/schema: FieldReaderConfig detects computed maps --- helper/schema/field_reader_config.go | 53 ++++++++++++---- helper/schema/field_reader_config_test.go | 73 +++++++++++++++++++++++ terraform/resource.go | 9 +++ 3 files changed, 125 insertions(+), 10 deletions(-) diff --git a/helper/schema/field_reader_config.go b/helper/schema/field_reader_config.go index 3c01e8de2..a6edef099 100644 --- a/helper/schema/field_reader_config.go +++ b/helper/schema/field_reader_config.go @@ -105,34 +105,67 @@ func (r *ConfigFieldReader) readField( } func (r *ConfigFieldReader) readMap(k string) (FieldReadResult, error) { - mraw, ok := r.Config.Get(k) + // We want both the raw value and the interpolated. We use the interpolated + // to store actual values and we use the raw one to check for + // computed keys. + mraw, ok := r.Config.GetRaw(k) if !ok { return FieldReadResult{}, nil } result := make(map[string]interface{}) + computed := false switch m := mraw.(type) { case []interface{}: - for _, innerRaw := range m { - for k, v := range innerRaw.(map[string]interface{}) { - result[k] = v + for i, innerRaw := range m { + for ik, _ := range innerRaw.(map[string]interface{}) { + key := fmt.Sprintf("%s.%d.%s", k, i, ik) + if r.Config.IsComputed(key) { + computed = true + break + } + + v, _ := r.Config.Get(key) + result[ik] = v } } case []map[string]interface{}: - for _, innerRaw := range m { - for k, v := range innerRaw { - result[k] = v + for i, innerRaw := range m { + for ik, _ := range innerRaw { + key := fmt.Sprintf("%s.%d.%s", k, i, ik) + if r.Config.IsComputed(key) { + computed = true + break + } + + v, _ := r.Config.Get(key) + result[ik] = v } } case map[string]interface{}: - result = m + for ik, _ := range m { + key := fmt.Sprintf("%s.%s", k, ik) + if r.Config.IsComputed(key) { + computed = true + break + } + + v, _ := r.Config.Get(key) + result[ik] = v + } default: panic(fmt.Sprintf("unknown type: %#v", mraw)) } + var value interface{} + if !computed { + value = result + } + return FieldReadResult{ - Value: result, - Exists: true, + Value: value, + Exists: true, + Computed: computed, }, nil } diff --git a/helper/schema/field_reader_config_test.go b/helper/schema/field_reader_config_test.go index 33672eff2..96028a89c 100644 --- a/helper/schema/field_reader_config_test.go +++ b/helper/schema/field_reader_config_test.go @@ -135,6 +135,79 @@ func TestConfigFieldReader_DefaultHandling(t *testing.T) { } } +func TestConfigFieldReader_ComputedMap(t *testing.T) { + schema := map[string]*Schema{ + "map": &Schema{ + Type: TypeMap, + Computed: true, + }, + } + + cases := map[string]struct { + Addr []string + Result FieldReadResult + Config *terraform.ResourceConfig + Err bool + }{ + "set, normal": { + []string{"map"}, + FieldReadResult{ + Value: map[string]interface{}{ + "foo": "bar", + }, + Exists: true, + Computed: false, + }, + testConfig(t, map[string]interface{}{ + "map": map[string]interface{}{ + "foo": "bar", + }, + }), + false, + }, + + "computed element": { + []string{"map"}, + FieldReadResult{ + Exists: true, + Computed: true, + }, + testConfigInterpolate(t, map[string]interface{}{ + "map": map[string]interface{}{ + "foo": "${var.foo}", + }, + }, map[string]ast.Variable{ + "var.foo": ast.Variable{ + Value: config.UnknownVariableValue, + Type: ast.TypeString, + }, + }), + 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 TestConfigFieldReader_ComputedSet(t *testing.T) { schema := map[string]*Schema{ "strSet": &Schema{ diff --git a/terraform/resource.go b/terraform/resource.go index 9dacbc7c5..5b9fbf7d2 100644 --- a/terraform/resource.go +++ b/terraform/resource.go @@ -134,6 +134,15 @@ func (c *ResourceConfig) Get(k string) (interface{}, bool) { return c.get(k, c.Raw) } +// GetRaw looks up a configuration value by key and returns the value, +// from the raw, uninterpolated config. +// +// The second return value is true if the get was successful. Get will +// not succeed if the value is being computed. +func (c *ResourceConfig) GetRaw(k string) (interface{}, bool) { + return c.get(k, c.Raw) +} + // IsComputed returns whether the given key is computed or not. func (c *ResourceConfig) IsComputed(k string) bool { _, ok := c.get(k, c.Config)