helper/schema: FieldReaderConfig detects computed maps
This commit is contained in:
parent
45f73e640f
commit
fa934d96d0
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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{
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue