helper/schema: FieldReaderConfig detects computed maps

This commit is contained in:
Mitchell Hashimoto 2015-04-21 22:07:52 +02:00
parent 45f73e640f
commit fa934d96d0
3 changed files with 125 additions and 10 deletions

View File

@ -105,34 +105,67 @@ func (r *ConfigFieldReader) readField(
} }
func (r *ConfigFieldReader) readMap(k string) (FieldReadResult, error) { 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 { if !ok {
return FieldReadResult{}, nil return FieldReadResult{}, nil
} }
result := make(map[string]interface{}) result := make(map[string]interface{})
computed := false
switch m := mraw.(type) { switch m := mraw.(type) {
case []interface{}: case []interface{}:
for _, innerRaw := range m { for i, innerRaw := range m {
for k, v := range innerRaw.(map[string]interface{}) { for ik, _ := range innerRaw.(map[string]interface{}) {
result[k] = v 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{}: case []map[string]interface{}:
for _, innerRaw := range m { for i, innerRaw := range m {
for k, v := range innerRaw { for ik, _ := range innerRaw {
result[k] = v 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{}: 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: default:
panic(fmt.Sprintf("unknown type: %#v", mraw)) panic(fmt.Sprintf("unknown type: %#v", mraw))
} }
var value interface{}
if !computed {
value = result
}
return FieldReadResult{ return FieldReadResult{
Value: result, Value: value,
Exists: true, Exists: true,
Computed: computed,
}, nil }, nil
} }

View File

@ -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) { func TestConfigFieldReader_ComputedSet(t *testing.T) {
schema := map[string]*Schema{ schema := map[string]*Schema{
"strSet": &Schema{ "strSet": &Schema{

View File

@ -134,6 +134,15 @@ func (c *ResourceConfig) Get(k string) (interface{}, bool) {
return c.get(k, c.Raw) 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. // IsComputed returns whether the given key is computed or not.
func (c *ResourceConfig) IsComputed(k string) bool { func (c *ResourceConfig) IsComputed(k string) bool {
_, ok := c.get(k, c.Config) _, ok := c.get(k, c.Config)