helper/schema: track map element counts
This adds "field.#" values to the state/diff with the element count of a map. This fixes a major issue around not knowing when child elements are computed when doing variable access of a computed map. Example, if you have a schema like this: "foo": &Schema{ Type: TypeMap, Computed: true, } And you access it like this in a resource: ${type.name.foo.computed-field} Then Terraform will error that "field foo could not be found on resource type.name". By adding that "foo.#" is computed, Terraform core will pick up that it WILL exist, so its okay.
This commit is contained in:
parent
41dabd7abc
commit
e5877543b2
|
@ -575,7 +575,7 @@ func (m schemaMap) diffMap(
|
||||||
|
|
||||||
// First get all the values from the state
|
// First get all the values from the state
|
||||||
var stateMap, configMap map[string]string
|
var stateMap, configMap map[string]string
|
||||||
o, n, _, _ := d.diffChange(k)
|
o, n, _, computedMap := d.diffChange(k)
|
||||||
if err := mapstructure.WeakDecode(o, &stateMap); err != nil {
|
if err := mapstructure.WeakDecode(o, &stateMap); err != nil {
|
||||||
return fmt.Errorf("%s: %s", k, err)
|
return fmt.Errorf("%s: %s", k, err)
|
||||||
}
|
}
|
||||||
|
@ -583,6 +583,48 @@ func (m schemaMap) diffMap(
|
||||||
return fmt.Errorf("%s: %s", k, err)
|
return fmt.Errorf("%s: %s", k, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the counts
|
||||||
|
oldLen, newLen := len(stateMap), len(configMap)
|
||||||
|
oldStr := strconv.FormatInt(int64(oldLen), 10)
|
||||||
|
|
||||||
|
// If the whole map is computed, then just say the # is computed and exit.
|
||||||
|
if computedMap {
|
||||||
|
diff.Attributes[k+".#"] = &terraform.ResourceAttrDiff{
|
||||||
|
Old: oldStr,
|
||||||
|
NewComputed: true,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the number of elements has changed. If we're computing
|
||||||
|
// a list and there isn't a config, then it hasn't changed.
|
||||||
|
changed := oldLen != newLen
|
||||||
|
if oldLen != 0 && newLen == 0 && schema.Computed {
|
||||||
|
changed = false
|
||||||
|
}
|
||||||
|
computed := oldLen == 0 && newLen == 0 && schema.Computed
|
||||||
|
if changed || computed {
|
||||||
|
countSchema := &Schema{
|
||||||
|
Type: TypeInt,
|
||||||
|
Computed: schema.Computed,
|
||||||
|
ForceNew: schema.ForceNew,
|
||||||
|
}
|
||||||
|
|
||||||
|
newStr := ""
|
||||||
|
if !computed {
|
||||||
|
newStr = strconv.FormatInt(int64(newLen), 10)
|
||||||
|
} else {
|
||||||
|
oldStr = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
diff.Attributes[k+".#"] = countSchema.finalizeDiff(
|
||||||
|
&terraform.ResourceAttrDiff{
|
||||||
|
Old: oldStr,
|
||||||
|
New: newStr,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// If the new map is nil and we're computed, then ignore it.
|
// If the new map is nil and we're computed, then ignore it.
|
||||||
if n == nil && schema.Computed {
|
if n == nil && schema.Computed {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -1205,6 +1205,11 @@ func TestSchemaMap_Diff(t *testing.T) {
|
||||||
|
|
||||||
Diff: &terraform.InstanceDiff{
|
Diff: &terraform.InstanceDiff{
|
||||||
Attributes: map[string]*terraform.ResourceAttrDiff{
|
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||||
|
"config_vars.#": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "0",
|
||||||
|
New: "1",
|
||||||
|
},
|
||||||
|
|
||||||
"config_vars.bar": &terraform.ResourceAttrDiff{
|
"config_vars.bar": &terraform.ResourceAttrDiff{
|
||||||
Old: "",
|
Old: "",
|
||||||
New: "baz",
|
New: "baz",
|
||||||
|
@ -1381,6 +1386,10 @@ func TestSchemaMap_Diff(t *testing.T) {
|
||||||
Old: "1",
|
Old: "1",
|
||||||
New: "0",
|
New: "0",
|
||||||
},
|
},
|
||||||
|
"config_vars.0.#": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "2",
|
||||||
|
New: "0",
|
||||||
|
},
|
||||||
"config_vars.0.foo": &terraform.ResourceAttrDiff{
|
"config_vars.0.foo": &terraform.ResourceAttrDiff{
|
||||||
Old: "bar",
|
Old: "bar",
|
||||||
NewRemoved: true,
|
NewRemoved: true,
|
||||||
|
@ -1663,6 +1672,31 @@ func TestSchemaMap_Diff(t *testing.T) {
|
||||||
|
|
||||||
Err: false,
|
Err: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// #43 - Computed maps
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"vars": &Schema{
|
||||||
|
Type: TypeMap,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: nil,
|
||||||
|
|
||||||
|
Config: nil,
|
||||||
|
|
||||||
|
Diff: &terraform.InstanceDiff{
|
||||||
|
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||||
|
"vars.#": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
NewComputed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Err: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
|
|
Loading…
Reference in New Issue